#pragma once

#include <iostream>

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <vector>
#include <queue>

#include "task.hpp"

using namespace std;

namespace PeocessPool
{
    enum error_code
    {
        READ_ERROR=1,
    };

    string errortos(int i)
    {
        string s;
        switch(i)
        {
            case READ_ERROR: 
            s="系统调用read调用失败!";
            break;
        }
        return s;
    }

    class WPipe // 描述管道
    {
        public:
        WPipe(int wfd, pid_t id, int i) : _wfd(wfd), _cpid(id)
        {
            _cname = "proc" + to_string(i);
        }
        int getwfd()
        {
            return _wfd;
        }
        pid_t getcpid()
        {
            return _cpid;
        }
        string getcname()
        {
            return _cname;
        }
        ~WPipe()
        {
        }

        private:
        string _cname; // 管道对应的字进程的名字
        int _wfd;      // 管道对应的写端fd
        pid_t _cpid;   // 对应子进程的pid
    };

    template <typename T>
    class proc_pool
    {
        static const int default_num = 5;

        void PerfTask(int rfd)
        {
            while (true)
            {
                T task;
                int n = read(rfd, &task, sizeof(task)); // 获取任务
                if (n > 0)                           // 任务获取成功
                {
                    cout<<"子进程："<<getpid()<<"执行任务："<<endl;
                    task(); // 执行任务
                }
                else if (n == 0) // 管道关闭了
                {
                    break;
                }
                else // read函数调用失败
                {
                    exit(READ_ERROR);
                }
            }
        }
        proc_pool(int n = default_num) : _proc_num(n), _isrunning(false), _i(0)
        {
        }
        proc_pool(const proc_pool& obj)=delete;
        proc_pool& operator=(const proc_pool&obj)=delete;
     public:
        static proc_pool<T>* Getobj(int n = default_num)
        {
            if(_This==nullptr)
            {
                _This=new proc_pool<T>(n);
            }
            return _This;
        }

        bool Start()
        {
            if (_isrunning == true) // 不能重复启动
            {
                return false;
            }

            _isrunning = true;
            // 创建子进程
            for (int i = 0; i <_proc_num; i++)
            {
                int fd[2];
                pipe(fd); // 创建管道

                int n = fork();
                if (n == 0)
                {
                    close(fd[1]); // 关闭写端文件描述符
                    for (auto e : _wpipeTable)
                    {
                        close(e.getwfd()); // 关闭不需要的文件描述符
                    }

                    PerfTask(fd[0]); // 子进程前往等待任务

                    exit(0); // 退出
                }
                close(fd[0]); // 关闭读端文件描述符
                _wpipeTable.emplace_back(fd[1], n, i + 1);

                cout << _wpipeTable.back().getcname() << "已经就绪" << endl;
            }
            return true;
        }

        bool Stop()
        {
            if (_isrunning == false) // 不能重复停止
            {
                return false;
            }
            _isrunning = false;

            for (auto e : _wpipeTable)
            {
                close(e.getwfd());//关闭管道写端

                int status=0;

                int n=waitpid(e.getcpid(), &status,0);//等待回收子进程
                if(n>0)//回收成功
                {
                    cout<<e.getcname()<<"回收成功"<<endl;

                    if(WIFEXITED(status))
                    {
                        if((WEXITSTATUS(status)!=0))//子进程因为错误退出
                        {
                            cout<<errortos(WEXITSTATUS(status))<<endl;
                        }
                    }
                }
                else//函数waitpid调用失败
                {
                    perror("waiptid:");
                }
            }
            return true;
        }

        bool PushFunc(const T &task) // 获取任务函数
        {
            // 使用轮巡派发任务，实现简单的负载均衡
            int n=write(_wpipeTable[_i].getwfd(), &task, sizeof(task));
            if(n>0)//写入成功
            {
                cout<<"向"<<_wpipeTable[_i].getcname()<<"任务写入成功"<<endl;
                _i++;
                _i %= _wpipeTable.size();
            }
            else if(n==0)//管道断开
            {
                cout<<_wpipeTable[_i].getcname()<<"管道异常断开！"<<endl;
                return false;
            }
            else//write系统调用失败
            {
                perror("write:");
                return false;
            }
            return true;
        }
        ~proc_pool()
        {
            Stop();
        }
     private:
        static proc_pool<T>* _This;
        int _proc_num;             // 子进程个数
        vector<WPipe> _wpipeTable; // 管理管道
        bool _isrunning;           // 是否运行
        int _i;                    // 轮巡下标
    };

    template <typename T>
    proc_pool<T>* proc_pool<T>::_This=nullptr;
}
